package com.winit.projectPlan.manager;

import com.alibaba.fastjson.JSONObject;
import com.winit.attachment.service.IAttachmentService;
import com.winit.common.CloudLinkSend.MqMsgType;
import com.winit.common.base.bean.ExecuteResult;
import com.winit.common.base.bean.Status;
import com.winit.common.base.web.BaseController;
import com.winit.common.util.DateGenerator;
import com.winit.commons.util.DateUtil;
import com.winit.common.util.TableIdUtil;
import com.winit.commons.util.HttpClientUtil;
import com.winit.commons.util.SeqGenerate;
import com.winit.common.CloudLinkSend.MsgSend;
import com.winit.projectPlan.model.ProjectPlan;
import com.winit.projectPlan.model.ProjectPlanStatus;
import com.winit.projectPlan.repository.ProjectPlanRepository;
import com.winit.projectPlan.repository.ProjectPlanRepositoryExt;
import com.winit.requirement.manager.BrdRequirementManager;
import com.winit.requirement.model.BrdRequirement;
import com.winit.requirement.repository.BrdRequirementRepository;
import com.winit.requirement.service.IBrdRequirementService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;

@Component
public class ProjectPlanMananger {
    private static Logger log = LoggerFactory.getLogger(ProjectPlanMananger.class);

    @Value("${url_beetle_plan}")
    private String BEETLE_PLAN_SERVER;
    @Value("${path_create_project_plan}")
    private String PATH_CREATE_PROJECT_PLAN;
    @Value("${path_del_project_plan}")
    private String PATH_DEL_PROJECT_PLAN;
    @Value("${path_add_project_plan_member}")
    private String PATH_ADD_PLAN_MEMBERS;
    @Value("${path_update_plan_info}")
    private String PATH_UPDATE_PLAN_INFO;

    @Autowired
    private MsgSend msgSend;

    @Autowired
    private ProjectPlanRepository projectPlanRepository;
    @Autowired
    private ProjectPlanRepositoryExt projectPlanRepositoryExt;
    @Autowired
    private IBrdRequirementService brdRequirementService;
    @Autowired
    private IAttachmentService attachmentService;
    @Autowired
    private BrdRequirementRepository reqRepository;
    @Autowired
    private BrdRequirementManager reqManager;

    public ExecuteResult<List<ProjectPlan>> getProjectPlans(String projectPlanId, String contain_finished, String userAccount, Date onlineTime, String keyword, Long startDate) {
        String projectPlanStatus = "N".equalsIgnoreCase(contain_finished) ? ProjectPlanStatus.COMPLETED.name() : null;
        //只能查询未删除的
        String sDate=null;
        if(null !=startDate){
            sDate=DateGenerator.getYYYY_MM_DD(startDate);
        }
        List<ProjectPlan> list = this.projectPlanRepository.getProjectPlans(projectPlanId, projectPlanStatus, "1", userAccount, onlineTime, keyword,sDate);
        ExecuteResult<List<ProjectPlan>> rs = new ExecuteResult<List<ProjectPlan>>();
        rs.setData(list);
        return rs;
    }

    public ExecuteResult<ProjectPlan> saveProjectPlan(ProjectPlan projectPlan) {
        ExecuteResult<ProjectPlan> rs = new ExecuteResult<ProjectPlan>();
        Map map = new HashMap();
        map.put("reqIds", projectPlan.getReqIds());
        /** 创建projectPlan操作 */
        if (null == projectPlan.getProjectPlanId()) {
            log.info("no project_plan_id found, creation will be executed...");
            rs = this.createProjectPlan(projectPlan);
            if ("0".equals(rs.getCode())) {
                msgSend.sendMsg(MqMsgType.PROJECT,map);
            }
            return rs;
        }
        /** 删除prd操作 */
        if ("0".equals(projectPlan.getProjectPlanIsDel())) {
            log.info("projectPlan will be delete, pp_id:" + projectPlan.getProjectPlanId());
            rs = this.deleteProjectPlan(projectPlan);
            return rs;
        }
        /** 到这里则为更新操作 */
        rs = this.updateProjectPlan(projectPlan);
        return rs;
    }

    /**
     * 创建prd，这里会生成新project_plan_id，并且会设置新建状态下的默认字段（如果上传有该字段，那么将会覆盖）
     *
     * @param projectPlan
     * @return 如果成功，返回code-0,data-带有project_plan_id的prd；若失败，code-1,desc-失败原因
     */
    public ExecuteResult<ProjectPlan> createProjectPlan(ProjectPlan projectPlan) {
        log.info("com.winit.projectPlan.manager.ProjectPlanMananger.createProjectPlan start.");
        ExecuteResult<ProjectPlan> rs = new ExecuteResult<ProjectPlan>();
        if (!this.canProjectPlanCreate(projectPlan, rs)) {       //不能创建
            log.error("创建project plan非法：" + rs.getDesc());
            return rs;
        }
        //默认未删除
        projectPlan.setProjectPlanIsDel("1");
        //默认创建时间
        if (null == projectPlan.getProjectPlanCreateTime()) {
            projectPlan.setProjectPlanCreateTime(DateUtil.getCurDate());
        }
        projectPlan.setProjectPlanId(TableIdUtil.createProjectPlanId());
        projectPlan.setProjectPlanNo("PJP" + SeqGenerate.createSerialNo());
        projectPlan.setProjectPlanStatus(ProjectPlanStatus.NEW.name());


        //调用beetle_plan新建projectPlan
        Map<String, String> params = new HashMap<>();
        params.put("end_date", DateUtil.formatDate(projectPlan.getProjectPlanOnlineTime(), "yyyy-MM-dd"));
        params.put("start_date", DateUtil.formatDate(projectPlan.getProjectPlanStartupTime(), "yyyy-MM-dd"));
        params.put("plan_code", projectPlan.getProjectPlanCode());
        params.put("plan_name", projectPlan.getProjectPlanName());
        params.put("token_id", projectPlan.getTokenId());
        params.put("teamMembers", projectPlan.getMemebers());
        params.put("desc", projectPlan.getProjectPlanDesc());
        try {
            String httpRs = HttpClientUtil.doPost(BEETLE_PLAN_SERVER + PATH_CREATE_PROJECT_PLAN, params);
            log.info("create beetle plan by projectPlan projectPlanId:" + projectPlan.getProjectPlanId() + ", rs:" + httpRs);
            JSONObject httpRsMap = JSONObject.parseObject(httpRs);
            if (httpRsMap.get("success") == null || (!"true".equalsIgnoreCase(httpRsMap.get("success").toString()))) {
                rs.setCode(BaseController.REQUEST_ERROR);
                rs.setDesc("创建project plan错误");
                return rs;
            }
//                ProjectPlan update= new ProjectPlan();
//                update.setProjectPlanId(projectPlan.getProjectPlanId());
//                update.setUplanId((String)httpRsMap.get("data"));
//                this.prdRepositoryExt.updatePrdById(update);
            projectPlan.setUplanId((String) httpRsMap.get("data"));
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            rs.setCode(BaseController.REQUEST_ERROR);
            rs.setDesc("创建project plan错误");
            return rs;
        }

        this.projectPlanRepository.save(projectPlan);
        if (!CollectionUtils.isEmpty(projectPlan.getReqIds())) {
            this.flushBrdRequirementsOfProjectPlan(projectPlan.getProjectPlanId(), projectPlan.getReqIds(), 1);
        }
        if (!CollectionUtils.isEmpty(projectPlan.getAttachmentIds())) {      //刷新attachment的附属关系
            this.attachmentService.flushRelationToOwner(projectPlan.getProjectPlanId(), projectPlan.getAttachmentIds(), 1);
        }
        rs.setData(projectPlan);
        log.info("com.winit.projectPlan.manager.ProjectPlanMananger.createProjectPlan end.");
        return rs;
    }

    /**
     * 根据prd_id删除该projectPlan，这里不会操作projectPlan其它字段
     *
     * @param projectPlan
     * @return 若成功，code-0, data-projectPlan；若失败， code-1,desc具体原因
     */
    private ExecuteResult<ProjectPlan> deleteProjectPlan(ProjectPlan projectPlan) {
        ExecuteResult<ProjectPlan> rs = new ExecuteResult<ProjectPlan>();
        if (!this.canProjectPlanDelete(projectPlan.getProjectPlanId(), rs)) {
            log.error(rs.getDesc());
            return rs;
        }
        ProjectPlan dbProjectPlan = this.projectPlanRepository.findOne(projectPlan.getProjectPlanId());
        //删除时不会更新其他字段
        ProjectPlan deleteItem = new ProjectPlan();
        deleteItem.setProjectPlanId(projectPlan.getProjectPlanId());
        deleteItem.setProjectPlanIsDel(projectPlan.getProjectPlanIsDel());
        this.projectPlanRepositoryExt.updateProjectPlanById(deleteItem);
        //删除brd_requirement与prd的关系
        this.flushBrdRequirementsOfProjectPlan(projectPlan.getProjectPlanId(), null, 2);
        //删除attachment与prd的关系
        this.attachmentService.flushRelationToOwner(projectPlan.getProjectPlanId(), null, 2);
        if (StringUtils.isEmpty(dbProjectPlan.getUplanId())) {
            rs.setData(projectPlan);
            return rs;
        }
        try {
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.append(BEETLE_PLAN_SERVER);
            stringBuilder.append(PATH_DEL_PROJECT_PLAN);
            stringBuilder.append("?");
            stringBuilder.append("token_id=");
            stringBuilder.append(projectPlan.getTokenId());
            stringBuilder.append("&plan_id=");
            stringBuilder.append(dbProjectPlan.getUplanId());
            String httpRs = HttpClientUtil.doGet(stringBuilder.toString());
            log.info("删除beetle plan结果，projectPlanId:" + projectPlan.getProjectPlanId() + ", http response:" + httpRs);
            JSONObject jsonObject = JSONObject.parseObject(httpRs);
            if (jsonObject.get("success") == null || (!"true".equalsIgnoreCase(jsonObject.get("success").toString()))) {
                rs.setCode(BaseController.REQUEST_ERROR);
                rs.setDesc("删除beetle plan错误");
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            rs.setCode(BaseController.REQUEST_ERROR);
            rs.setDesc("删除beetle plan错误");
        }
        rs.setData(projectPlan);
        return rs;
    }

    /**
     * 根据prd_id更新该prd
     *
     * @param projectPlan
     * @return 若更新成功，则返回code-0, data-projectPlan；若失败，code-1,desc返回具原因
     */
    private ExecuteResult<ProjectPlan> updateProjectPlan(ProjectPlan projectPlan) {
        ExecuteResult<ProjectPlan> rs = new ExecuteResult<ProjectPlan>();
        ProjectPlan dbProjectPlan = this.projectPlanRepository.findOne(projectPlan.getProjectPlanId());
        if (!this.canProjectPlanUpdate(projectPlan, rs)) {
            return rs;
        }
        //老数据没有beetle plan信息
        boolean hasBeetlePlanInfo = !StringUtils.isEmpty(dbProjectPlan.getUplanId());
        if ((null != projectPlan.getMemebers()) && hasBeetlePlanInfo) {
            Map<String, String> addPlanMemberParams = new HashMap<>();
            addPlanMemberParams.put("token_id", projectPlan.getTokenId());
            addPlanMemberParams.put("list", projectPlan.getMemebers());
            addPlanMemberParams.put("plan_id", dbProjectPlan.getUplanId());
            String url = BEETLE_PLAN_SERVER + PATH_ADD_PLAN_MEMBERS;
            try {
                String httpRs = HttpClientUtil.doPost(url, addPlanMemberParams);
                log.info("update plan members for projectPlan, projectPlanId:" + projectPlan.getProjectPlanId() + ",http response:" + httpRs);
                JSONObject jsonObject = JSONObject.parseObject(httpRs);
                if (jsonObject.get("success") == null || (!"true".equalsIgnoreCase(jsonObject.get("success").toString()))) {
                    rs.setCode(BaseController.REQUEST_ERROR);
                    rs.setDesc("更新plan members错误" + jsonObject.get("msg"));
                    return rs;
                }
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                rs.setCode(BaseController.REQUEST_ERROR);
                rs.setDesc("更新plan members错误");
                return rs;
            }
        }
        Map<String, String> updatePlanInfoParams = new HashMap<>();
        if (null != projectPlan.getProjectPlanStartupTime()) {
            updatePlanInfoParams.put("start_date", DateUtil.formatDate(projectPlan.getProjectPlanStartupTime(), "yyyy-MM-dd"));
        }
        if (null != projectPlan.getProjectPlanOnlineTime()) {
            updatePlanInfoParams.put("end_date", DateUtil.formatDate(projectPlan.getProjectPlanOnlineTime(), "yyyy-MM-dd"));
        }
        if (null != projectPlan.getProjectPlanName()) {
            updatePlanInfoParams.put("plan_name", projectPlan.getProjectPlanName());
        }
        if (null != projectPlan.getProjectPlanCode()) {
            updatePlanInfoParams.put("plan_code", projectPlan.getProjectPlanCode());
        }
        if ((!updatePlanInfoParams.isEmpty()) && hasBeetlePlanInfo) {

//        updatePlanInfoParams.put("token_id", projectPlan.getTokenId());
//        updatePlanInfoParams.put("plan_id", dbProjectPlan.getUplanId());
            String url = BEETLE_PLAN_SERVER + PATH_UPDATE_PLAN_INFO;
            StringBuilder stringBuilder = new StringBuilder(url);
            stringBuilder.append("?token_id=").append(projectPlan.getTokenId());
            stringBuilder.append("&plan_id=").append(dbProjectPlan.getUplanId());
            for (Map.Entry<String, String> entry : updatePlanInfoParams.entrySet()) {
                stringBuilder.append("&").append(entry.getKey()).append("=").append(entry.getValue());
            }
            try {
                JSONObject jsonObject = HttpClientUtil.doGetForJson(stringBuilder.toString());
                log.info("update plan info for projectPlan, projectPlanId:" + projectPlan.getProjectPlanId() + ",http response:" + jsonObject);
                if (jsonObject.get("success") == null || (!"true".equalsIgnoreCase(jsonObject.get("success").toString()))) {
                    rs.setCode(BaseController.REQUEST_ERROR);
                    rs.setDesc("更新plan info错误:" + jsonObject.get("msg"));
                    return rs;
                }
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                rs.setCode(BaseController.REQUEST_ERROR);
                rs.setDesc("更新beetle plan info错误");
                return rs;
            }
        }
        this.projectPlanRepositoryExt.updateProjectPlanById(projectPlan);
        //注意这里不可以用isEmpty方法，当reqIds不为NULL时就应该进行操作，支持为empty进行清空操作
        if (null != projectPlan.getReqIds()) {
            this.flushBrdRequirementsOfProjectPlan(projectPlan.getProjectPlanId(), projectPlan.getReqIds(), 3);
        }
        //注意这里不可以用isEmpty方法，当attachmentIds不为NULL时就应该进行操作，支持为empty进行清空操作
        if (null != projectPlan.getAttachmentIds()) {
            this.attachmentService.flushRelationToOwner(projectPlan.getProjectPlanId(), projectPlan.getAttachmentIds(), 3);
        }

        rs.setData(projectPlan);
        return rs;
    }

    /**
     * 判定是否可以更新projectPlan
     *
     * @param projectPlan
     * @param executeResult 若不能更新，则详细原因记入该对象，code为1
     * @return true-可以更新，false-不能更新
     */
    private boolean canProjectPlanUpdate(ProjectPlan projectPlan, ExecuteResult executeResult) {
        //其中的brd_requirement被其它prd占用
        if ((!CollectionUtils.isEmpty(projectPlan.getReqIds())) && this.checkBrdRequirementOccupiedByOtherProjectPlan(projectPlan.getProjectPlanId(), projectPlan.getReqIds(), executeResult)) {
            return false;
        }
        if (!StringUtils.isEmpty(projectPlan.getProjectPlanName())) {
            //修改产品计划时  名称不能重复
            List<ProjectPlan> list = this.projectPlanRepository.findByProjectPlanName(projectPlan.getProjectPlanName());
            if (null == list || list.size() == 0) {
                return true;
            }
            if (list.size() == 1 && (projectPlan.getProjectPlanId()).equals(list.get(0).getProjectPlanId())) {
                return true;
            }
            executeResult.setCode(BaseController.REQUEST_ERROR);
            executeResult.setDesc("产品计划名称不能重复");
            return false;
        }
        return true;
    }

    /**
     * 判定是否可以删除该 projectPlan
     *
     * @param projectPlanId
     * @param executeResult，若不能删除，详细原因将记入该对象，code为1
     * @return true-可以删除，false-不能删除
     */
    private boolean canProjectPlanDelete(String projectPlanId, ExecuteResult executeResult) {
        ProjectPlan entity = this.projectPlanRepository.findOne(projectPlanId);
        if (null == entity) {
            executeResult.setCode(BaseController.REQUEST_ERROR);
            executeResult.setDesc("delete failed, no projectPlan foud for this project_plan_id:" + projectPlanId);
            return false;
        }
        return this.canProjectPlanDelete(entity, executeResult);
    }

    /**
     * 检测prd是否可以删除
     *
     * @param projectPlan
     * @param executeResult，当发生不能删除时，返回不能删除的原因以及code:1
     * @return true-可以删除， false不能删除
     */
    private boolean canProjectPlanDelete(ProjectPlan projectPlan, ExecuteResult executeResult) {
        if (ProjectPlanStatus.COMPLETED.name().equals(projectPlan.getProjectPlanStatus())) {     //已完成的不能删除
            executeResult.setCode(BaseController.REQUEST_ERROR);
            executeResult.setDesc("delete failed, this projectPlan has completed already, project_plan_id" + projectPlan.getProjectPlanId());
            return false;
        }
        if ("0".equals(projectPlan.getProjectPlanIsDel())) {        //已经删除的拒绝重复操作
            executeResult.setCode(BaseController.REQUEST_ERROR);
            executeResult.setDesc("delete failed, this projectPlan has been deleted already, project_plan_id" + projectPlan.getProjectPlanId());
            return false;
        }
        return true;
    }

    /**
     * @param projectPlan
     * @param executeResult 当不能创建时，返回不能创建的原因以及code
     * @return true-可以创建, false-不能创建
     */
    private boolean canProjectPlanCreate(ProjectPlan projectPlan, ExecuteResult<ProjectPlan> executeResult) {
        //其中的brd_requirement被其它prd占用
        if ((!CollectionUtils.isEmpty(projectPlan.getReqIds())) && this.checkBrdRequirementOccupiedByOtherProjectPlan(projectPlan.getProjectPlanId(), projectPlan.getReqIds(), executeResult)) {
            return false;
        }
        if ((!StringUtils.isEmpty(projectPlan.getProjectPlanName())) && (!CollectionUtils.isEmpty(this.projectPlanRepository.findByProjectPlanName(projectPlan.getProjectPlanName())))) {
            executeResult.setCode(BaseController.REQUEST_ERROR);
            executeResult.setDesc("projectPlan名称不能重复");
            return false;
        }
        if (StringUtils.isEmpty(projectPlan.getProjectPlanCode())) {
            executeResult.setCode(BaseController.REQUEST_ERROR);
            executeResult.setDesc("projectPlanCode不能为空");
            return false;
        }
        if (null != this.projectPlanRepository.findByProjectPlanCode(projectPlan.getProjectPlanCode())) {
            executeResult.setCode(BaseController.REQUEST_ERROR);
            executeResult.setDesc("projectPlanCode重复");
            return false;
        }
        return true;
    }

    /**
     * 这里判定涉及的brd_requirement是否已被其他projectPlan占用
     *
     * @param projectPlanId
     * @param reqIds
     * @return 占用返回true, 未占用返回false
     */
    private boolean checkBrdRequirementOccupiedByOtherProjectPlan(String projectPlanId, List<String> reqIds, ExecuteResult executeResult) {
        List<BrdRequirement> requirements = this.brdRequirementService.searchBrdRequirementsByReqIds(reqIds);
        if (CollectionUtils.isEmpty(requirements)) {
            return false;
        }
        for (BrdRequirement brdRequirement : requirements) {
            if (null != brdRequirement.getProjectPlanId()) {     //prd为null的brd_requirement是未被占用的，这里只检查有prd_id的
                if (!brdRequirement.getProjectPlanId().equals(projectPlanId)) {      //prd与当前prd_id不同
                    ProjectPlan occupiedProjectPlan = this.projectPlanRepository.findOne(brdRequirement.getProjectPlanId());
                    if (null != occupiedProjectPlan && (!"0".equals(occupiedProjectPlan.getProjectPlanIsDel()))) {     //占用的prd未删除,判定占用
                        executeResult.setCode(BaseController.REQUEST_ERROR);
                        log.error("com.winit.projectPlan.manager.ProjectPlanMananger.checkBrdRequirementOccupiedByOtherProjectPlan 需求" + brdRequirement.getReqId() + "关联了" + brdRequirement.getProjectPlanId());
                        executeResult.setDesc("需求已经关联了开发计划");
                        return true;
                    }
                }
            }
        }
        return false;
    }

    /**
     * 刷新brd_requirement与prd的关联关系，这里会先删除其关联关系 ，再新建其关联关系
     *
     * @param projectPlanId
     * @param reqIds
     * @param operationMode 1-新增prd, 2-删除prd, 3-修改prd
     */
    private void flushBrdRequirementsOfProjectPlan(String projectPlanId, List<String> reqIds, int operationMode) {
        this.brdRequirementService.flushBrdRequirementsOfProjectPlan(projectPlanId, reqIds, operationMode);
    }

    public ExecuteResult updateProjectPlanReq(String projectPlanId, List<String> _reqIds, Integer optMode) {
        ExecuteResult executeResult = new ExecuteResult();
        boolean isRemove = -1 == optMode.intValue();
        for (String reqId : _reqIds) {
            if (isRemove) {
                this.brdRequirementService.updateProjectPlanIdAndBrdStatusByProjectPlanId(reqId, Status.DISSOCIATION.name(), null);
            } else {
                this.brdRequirementService.updateProjectPlanIdAndBrdStatusByProjectPlanId(reqId, Status.P_PLAN.name(), projectPlanId);
            }
        }
        return executeResult;
    }

    public void dealUPlanOnline(String uplanId) {
        log.info("com.winit.projectPlan.manager.ProjectPlanMananger.dealUPlanOnline uplanId=" + uplanId);
        ProjectPlan plan = projectPlanRepository.findByUplanId(uplanId);
        if (null == plan) {
            log.error("com.winit.projectPlan.manager.ProjectPlanMananger.dealUPlanOnline 未找到对应项目 uplanId=" + uplanId);
            return;
        }
        List<BrdRequirement> list = reqRepository.findByProjectPlanId(plan.getProjectPlanId());
        List<String> reqIdLst = new ArrayList<>();
        for (BrdRequirement req : list) {
            reqIdLst.add(req.getReqId());
        }
        reqManager.operateForReqOnline(reqIdLst);
    }


}
